#ifdef WIN32

#if _MSC_VER < 1300 
#pragma warning( disable : 4786 )
#endif 

#if _MSC_VER > 1300 
#pragma warning( disable : 4996 )
#endif

#include <windows.h>

#endif

#include <string.h>
#include <string>
#include <map>
#include "ncrypt_wchar.h"
#include "ncrypt_string.h"

#ifdef _WIN32_WCE
#define strdup _strdup
#endif

using namespace std;

class memory
{
	string	m_file;
	int		m_line;
	string	m_func;
	int		m_len;
	void	*m_mem;

public:

	memory(const char* file, int line, const char* func, int len, void* mem)
	{
		m_file = file;
		m_line = line;
		m_func = func;
		m_len = len;
		m_mem = mem;
	}

	void print_alloc()
	{
#ifdef _ENABLE_ALLOC_LOG
		fprintf(stderr, "alloc     : %p(%d) in %s(%d):%s\n", m_mem, m_len, m_file.c_str(), m_line, m_func.c_str());
#endif 
	}

	void print_not_free()
	{
		fprintf(stderr, "not freed : %p(%d) in %s(%d):%s\n", m_mem, m_len, m_file.c_str(), m_line, m_func.c_str());
	}

	void print_free(char* file, int line)
	{
#ifdef _ENABLE_ALLOC_LOG
		fprintf(stderr, "free      : %p(%d) in %s(%d) - %s(%d):%s\n", m_mem, m_len,
			file, line, m_file.c_str(), m_line, m_func.c_str());
#endif 
	}

	memory& operator = (memory& m)
	{
		if ( this != &m )
		{
			m_file = m.m_file;
			m_line = m.m_line;
			m_func = m.m_func;
			m_len = m.m_len;
			m_mem = m.m_mem;
		}

		return *this;
	}
};

map<void*, memory> nmalloc_memory_map;

#define INSERT(f) \
	memory m(file, line, #f, len, mem); \
	m.print_alloc(); \
	nmalloc_memory_map.insert(pair<void*, memory>(mem, m))

void *ncalloc(char* file, int line, size_t nmemb, size_t size)
{
	int len = nmemb * size;
	void* mem = calloc(nmemb, size);
	INSERT(calloc);
	return mem;
}

void *nmalloc(char* file, int line, size_t size)
{
	int len = size;
	void* mem = malloc(size);
	INSERT(malloc);
	return mem;
}

void *nrealloc(char* file, int line, void *ptr, size_t size)
{
	map<void*, memory>::iterator it = nmalloc_memory_map.find(ptr);

	if ( it == nmalloc_memory_map.end() )
	{
		fprintf(stderr, "realloc   : invalid address %p in %s(%d)\n", ptr, file, line);
	}
	else
	{
		it->second.print_free(file, line);
		nmalloc_memory_map.erase(it);
	}

	int len = size;
	void* mem = realloc(ptr, size);
	INSERT(realloc);
	return mem;
}

char *nstrdup(char* file, int line, const char *s)
{
	int len = strlen(s)+1;
	char* mem = strdup(s);
	INSERT(strdup);
	return mem;
}

LPWSTR n_wcsdup(char* file, int line, LPCWSTR s)
{
	int len = _wcslen(s)+1;
#ifdef WIN32
	WCHAR* mem = _wcsdup(s);
#else
	WCHAR* mem = _ncrypt_wcsdup(s);
#endif
	INSERT(_wcsdup);
	return mem;
}

#if !defined(WIN32) && !defined(FreeBSD) && !defined(__FreeBSD__)

char *nstrndup(char* file, int line, const char *s, size_t n)
{
	int len = n+1;
	char* mem = strndup(s, n);
	INSERT(strndup);
	return mem;
}

#endif

void nfree(char* file, int line, void *ptr)
{
	map<void*, memory>::iterator it = nmalloc_memory_map.find(ptr);

	if ( it == nmalloc_memory_map.end() )
	{
		fprintf(stderr, "free      : invalid address %p in %s(%d)\n", ptr, file, line);
	}
	else
	{
		it->second.print_free(file, line);
		nmalloc_memory_map.erase(it);
	}
}

void show_malloc_status()
{
	fprintf(stderr, "========== CURRENT NOT FREED MEMORY ===========\n");
	for ( map<void*, memory>::iterator it = nmalloc_memory_map.begin() ; 
		it != nmalloc_memory_map.end() ; it++ )
	{
		it->second.print_not_free();
	}
	fprintf(stderr, "===============================================\n");
}
